<?php
/**
 * Zead
 *
 * LICENSE	
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.opensource.org/licenses/bsd-license.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to eu@marcelomx.com so we can send you a copy immediately.
 *
 * @category   Zead
 * @author     Marcelo Rodrigues Gonzaga <eu@marcelomx.com>
 * @copyright  Copyright (c) 2008 Marcelo Rodrigues Gonzaga
 * @link       http://code.google.com/p/zead 
 * @license    http://www.opensource.org/licenses/bsd-license.php     New BSD License
 *
 **/


/** @see Zead_Uri **/
require_once 'Zead/Uri.php';

/** @see Zead_PagesRange **/
require_once 'Zead/PagesRange.php';

/**
 * @category   Zead
 * @package    Zead_Manifest
 * @copyright  Copyright (c) 2008 Marcelo Rodrigues Gonzaga 
 * @license    http://www.opensource.org/licenses/bsd-license.php     New BSD License 
 */
class Zead_Manifest_Util
{		
	/**
	 * Tenta encontrar o recurso no metadados de acordo com o link atual acessado. Retorna
	 * o objeto/recurso, se encontrado, do contrário, retorna falso.
	 * 
	 * @param Zead_Metadata_Data_Abstract $metadata
	 * @param string $basePath O diretório base padrão para resolver os caminhos do arquivo do link
	 * @param string $requestUri O endereço do arquivo acessado atualmente.
	 * @return Zead_Metadata_Data_Content|boolean
	 */
	public static function findCurrent($contents, $scriptPath, $scriptName = null)
	{			
		foreach ($contents as $content) {
			$contentLinks = self::getLinks($content, $scriptPath);
			
			foreach ($contentLinks as $requestLink) {
				if ($requestLink == $scriptName) {
					return $content;
				}
			}
			// Procurando no subrecursos
			$childContent = self::findCurrent($content->getChildren(), $scriptPath, $scriptName);
				
			if ($childContent !== false) {
				return $childContent;
			} 			
		}
		
		return false;
	}	
	
	/**
	 * Retorna o recurso atual de acordo com a URL
	 * 
	 * @return Zead_Metadata_Data_Content
	 */
	public function getCurrent()
	{
		return self::findCurrent($this->_storage->getData(), 
			$this->_request->getBasePath(), 
			$this->_request->getRequestUri());
	}
	
	/**
	 * Retorna a lista de links para um recurso
	 * 
	 * @param Zead_Manifest_Content
	 * @param string $requestUri O endereço URI que servirá de base para formatar o endereço final do link
	 * @param array  $bindQuery  Os parametros HTTP que devem ser aplicados a cada link.
	 * 
	 * @return array A lista de links formatados.
	 */
	public static function getLinks(Zead_Manifest_Content $content, $requestUri = null, array $bindQuery = array()) 
	{
		$links = array();		
		$baseDir = self::getContentBaseDirectory($content);
		$contentFiles = self::getContentFiles($content);
		
		foreach($contentFiles as $fileName) {
			if ($baseDir != '') {
				$fileName = $baseDir . '/' . $fileName;
			}
			$links[] = Zead_Uri::filter($fileName, $requestUri, $bindQuery);
		}
		
		return $links;
	}		
	
	
	/**
	 * Returns the page range list
	 *
	 * @param Zead_Manifest_Content
	 * @param string $baseUri
	 * @param array  $bindQuery
	 */
	public static function getPages()
	{
		$pages = new Zead_PagesRange();
		
		$pages->append($page);
	}
	
	/**
	 * Retorna a lista de arquivos para um recurso
	 * 
	 * @param Zead_Manifest_Content $content
	 * @return array
	 */
	public static function getFiles(Zead_Manifest_Content $content, $basePath = null) 
	{	
		$files = array();
		$baseDir = self::getContentBaseDirectory($content);
		$contentFiles = self::getContentFiles($content);
		
		foreach ($contentFiles as $fileName) {
			if ($baseDir != '') {
				$fileName = $baseDir .'/'. $fileName;
			}
			$fileName = self::findRealFile($fileName,$basePath);
			$files[] = $fileName;
		}
		
		return $files;
	}
	
	public static function getContentStaticFiles($content, $basePath)
	{
		$filesRange = self::getContentPages($content);
		$baseDirectory = self::getContentBaseDirectory($content);
		
		foreach ($filesRange as $file) {
			if ($baseDirectory != '') {
				$file->url = $baseDirectory . '/'. $file->url;
			}
			$file->url = self::findRealFile($file->url, $basePath);
		}
		
		return $filesRange;
	}	

	
	/**
	 *  Descobre e retorna o caminho de um arquivo no sistema de arquivos a partir de um
	 *  caminho de diretório especificado, de acordo com os seus níveis.
	 * 
	 * @param string $fileName
	 * @param string $basePath
	 * @return string
	 */
	
	public static function findRealFile($fileName, $basePath) 
	{
		$basePath = str_replace("\\", "//", $basePath);
		$fileName = str_replace("\\", "//", $fileName);
		
		if (is_file($basePath)) {
			$basePath = dirname($basePath);
		}
		if (strtoupper(substr(PHP_OS,0,3)) == 'WIN') {
			$basePath = str_replace("/", "\\", $basePath);
			$fileName = str_replace("/","\\", $fileName);
		}
		if (substr($fileName,0,2) == '.' . DIRECTORY_SEPARATOR) {
			$fileName = substr($fileName,2);
		}
		if (substr($fileName,0,1) == DIRECTORY_SEPARATOR) {
			return $fileName;
		}
		$filePaths = explode(DIRECTORY_SEPARATOR, $fileName);
		$basePaths = explode(DIRECTORY_SEPARATOR, $basePath);
		$countLevels = array_count_values($filePaths);
		$count = (int) $countLevels['..'];
		
		$basePaths = implode(DIRECTORY_SEPARATOR, array_slice($basePaths,0,sizeof($basePaths)-$count));
		$filePaths = implode(DIRECTORY_SEPARATOR, array_slice($filePaths,$count,sizeof($filePaths)));
		$fileName  = $basePaths . DIRECTORY_SEPARATOR . $filePaths;
		
		return $fileName;
	}
	
	public static function getContentHttpPages($content, $baseUri, array $bindQuery = array(), 
		$namePrefix = 'pagina_', $fileExtension = '.php', $titlePrefix = 'Página') {
		
		$pagesRange = self::getContentPages($content);
		$baseDirectory = self::getContentBaseDirectory($content);
		
		foreach ($pagesRange as $page) {
			if ($baseDirectory != '') {
				$page->url = $baseDirectory . '/'. $page->url;
			}
			$page->url = Zead_Uri::filter($page->url, $baseUri, $bindQuery);
		}
		
		return $pagesRange;
	}
	
	public static function getContentParentHttpPages($content, $baseUri, $bindQuery)
	{
	}
		
	/**
	 * Mounts the pagesRange from a content. Only the single.
	 *
	 * @param Zead_Manifest_Content
	 * @param string $namePrefix	 
	 * @param string $fileExtension	 
	 * @param string $titlePrefix
	 * @return Zead_PagesRange
	 */
	public static function getContentPages($content, $pageNamePrefix = 'pagina_', $fileExtension = '.php', $pageTitlePrefix = 'Página ')
	{	
		$pagesRange = new Zead_PagesRange();
		$fileExtension = '.' . ltrim($fileExtension, '.');
		
		// If has pages number, create the pageNames
		if (($pages = (int) $content->getAttr('pages')) > 0 && ($file = $content->getAttr('file')) == '') {
			for ($i = 1; $i <= $pages; $i++) {			
				$currentPageNumber = self::normalizePageNumber($i);
				$fileName = $pageNamePrefix . $currentPageNumber . $fileExtension;
				$pageTitle = $pageTitlePrefix . $currentPageNumber;
				$pagesRange->append($fileName, $i, $pageTitle);
			}
			return $pagesRange;
		}
		// If no pages, gets the page from attr name
		$fileName = $content->getAttr('name');
		
		// If has attr file, gets the name from it.
		if ($file != '') $fileName = $basename($file);
		
		// Add to range
		$fileName = rtrim($fileName, $fileExtension) . $fileExtension;
		$pageTitle = $content->title;
		$pagesRange->append($fileName, $pageTitle, $pageTitle);
		
		return $pagesRange;
	}
	
	/**
	 * Normalize a page number, transforms in integer value and
	 * convert in an string with decimal zero prefix.
	 *
	 * @param  int|string $pageNumber
	 * @return string
	 */
	public static function normalizePageNumber($pageNumber)
	{
		$pageNumber = (int) $pageNumber;
		
		if ($pageNumber < 10)  {
			$pageNumber = '0'. $pageNumber;
		}
		
		return (string) $pageNumber;
	}
	
	public static function getContentFiles(Zead_Manifest_Content $content)
	{
		$files = array();
		$pages = $content->getAttr('pages');
		$file  = $content->getAttr('file');
		
		// Calcula pelo atributo pages		
		if ($pages > 0 && $file == '') {
			for ($i = 1; $i <= $pages; $i++) {
				$pageNumber = $i;
				if ($i < 10) $pageNumber = '0' . $i;
				$pageName = 'page_' . $pageNumber . '.php'; 
				$files[] = $pageName;
			}
			return $files;
		}
		// Calcula o nome pelo atributo name ou pelo nome do arquivo passado.
		$pageName = $content->getAttr('name');
		// Se foi usado nome de arquivo, entao ele sera usado como nome do arquivo
		if ($file != '') {
			$pageName = basename($file);
		}
		$files[] = $pageName . '.php';
		
		return $files;		
	}
	
	/**
	 * Retorna a string contendo o diretório base de um recurso no metadados.
	 * 
	 * @param Zead_Manifest_Content $content
	 */
	public static function getContentBaseDirectory($content)
	{
		$baseDirectory = null;
		$path = $content->getAttr('path');
		
		// If folder setted		
		if (($directory = $content->getAttr('dir')) !== null) {
			if (substr($directory, 0, 1) == '/') { // Absolutize path
				$path = 'absolute';
			}
			$baseDirectory = $directory;
		}
		// If baseDir is not null		
		if ($baseDirectory == null && ($file = $content->getAttr('file')) != '') {
			$baseDirectory = dirname($file);
			
			if ($baseDirectory == '.') {
				$baseDirectory = '';
			} else {
				$baseDirectory .= '/';
			}
		} else if ($baseDirectory == null && $content->getAttr('pages') > 0) {
			$baseDirectory = $content->getAttr('name');
		}
		
		// The path is relative, so, we're resolving the relative paths		
		if ($path != 'absolute' && $content->hasParent()) {
			$parentContent = $content->getParent();
			$parentBaseDirectory = self::getContentBaseDirectory($parentContent);
			
			if ($baseDirectory == null) {
				$baseDirectory = $parentContent->getAttr('name');
				
				if ($parentBaseDirectory != '') {
					$baseDirectory = $parentBaseDirectory . '/' . $baseDirectory;
				}
			} else if ($parentBaseDirectory != null) {
				$parentBaseDirectory .=  '/' . $parentContent->getAttr('name');
				$countLevels = substr_count($baseDirectory, '../');
				$parentPaths  = explode("/", $parentBaseDirectory);
				
				if ($countLevels >= 1 && $countLevels <= count($parentPaths)) {
					$parentBaseDirectory = join('/',array_slice($parentPaths,0,-$countLevels,true));
					$baseDirectory = str_replace('../', '', $baseDirectory);
					$countLevels = 0;
				}
				if ($parentBaseDirectory != '' && $countLevels == 0) {
					$baseDirectory = $parentBaseDirectory 
						. ($baseDirectory != '' 
							? '/' . $baseDirectory 
							: '');
				}
			} else if ($parentBaseDirectory == null) {
				if (((int) $content->getAttr('pages')) > 0) {
					$parentPaths = array();
					$parentContents = $content->getParents();
					
					foreach ($parentContents as $parent) {
						$parentPaths[] = $parent->getAttribute('name');
					}
					$parentPaths = join('/',$parentPaths);
					$baseDirectory = $parentPaths 
						. ($baseDirectory != '' 
							? '/' . $baseDirectory 
							: '');
				}
			}
		}
		
		// Format the final basedir
		if ($baseDirectory != '' && strlen($baseDirectory) > 1 && substr($baseDirectory,-1,1) == '/') {
			$baseDirectory = substr($baseDirectory,0,strlen($baseDirectory)-1);
		}		
		
		return $baseDirectory;			
	}
}
